package openglhandmaid
{
	import flash.geom.Vector3D;
	import flash.display.BitmapData;

	public class Bresenham
	{
		public function line(x0:int, y0:int, x1:int, y1:int, image:BitmapData, color:Number):void
		{
			var t:Number;
			var steep:Boolean = false;
			
			if(Math.abs(x0-x1) < Math.abs(y0-y1))
			{// swap
				t = x0;
				x0 = y0;
				y0 = t;
				
				t = x1;
				x1 = y1;
				y1 = t;
				
				steep = true;
			}
			if(x0 > x1)
			{// swap
				t = x0;
				x0 = x1;
				x1 = t;
				
				t = y0;
				y0 = y1;
				y1 = t;
			}
			var dx:int = x1-x0;
			var dy:int = y1-y0;
			var derror2:int = Math.abs(dy)*2;
			var error2:int = 0;
			
			var dx2:int = dx * 2;
			var incY:int = (y1>y0?1:-1);
			
			var y:int = y0;
			var x:int = x0;
			
			if(steep)
			{
				for (x=x0; x<=x1; x++)
				{
					image.setPixel(y, x, color);
					error2 += derror2;
					if (error2 > dx) 
					{
				        y += incY;
				        error2 -= dx2;
				    }
				}
			}
			else
			{
				for (x=x0; x<=x1; x++)
				{
					image.setPixel(x, y, color);
					error2 += derror2;
					if (error2 > dx) 
					{
				        y += incY;
				        error2 -= dx*2;
				    }
				}
			}
		}
		public function triangleWithUV(t0:Vector3D, t1:Vector3D, t2:Vector3D, uv0:Vector3D, uv1:Vector3D, uv2:Vector3D, texture:BitmapData, image:BitmapData, color:Number, zbuffer:Array):void
		{
			if (t0.y==t1.y && t0.y==t2.y) return; // i dont care about degenerate triangles
		   
			// sort the vertices, t0, t1, t2 lower-to-upper (bubblesort yay!)
			/*
			var arr:Array = [t0, t1, t2];
				arr.sort(function(p0:Vector3D, p1:Vector3D):int{
					if(p0.y > p1.y){ return 1; }
					else{ return -1; }
				});
			t0 = arr[0];
			t1 = arr[1];
			t2 = arr[2];
			*/
			
			var vectorTemp:Vector3D;
				
			if(t0.y > t1.y)
			{
				vectorTemp = t0;
				t0 = t1;
				t1 = vectorTemp;
				
				vectorTemp = uv0;
				uv0 = uv1;
				uv1 = vectorTemp;
			}
			if(t0.y > t2.y)
			{
				vectorTemp = t0;
				t0 = t2;
				t2 = vectorTemp;
				
				vectorTemp = uv0;
				uv0 = uv2;
				uv2 = vectorTemp;
			}
			if(t1.y > t2.y)
			{
				vectorTemp = t1;
				t1 = t2;
				t2 = vectorTemp;
				
				vectorTemp = uv1;
				uv1 = uv2;
				uv2 = vectorTemp;
			}
			
			// ------------
		
			var segment_height:int;
			var alpha:Number;
			var beta:Number;
			var A:Vector3D = new Vector3D();
			var B:Vector3D = new Vector3D();			
        	var P:Vector3D = new Vector3D();
        	
        	var uvA:Vector3D = new Vector3D();
        	var uvB:Vector3D = new Vector3D();
        	var uvP:Vector3D = new Vector3D();
        	
			var second_half:Boolean;
			// ------------
			
			var total_height:int = t2.y-t0.y;
			
			var dy1y0:Number = t1.y-t0.y;
			var dy2y1:Number = t2.y-t1.y;
			var dy2y0:Number = t2.y-t0.y;
			
			var dx1x0:Number = t1.x-t0.x;
			var dx2x1:Number = t2.x-t1.x;
			var dx2x0:Number = t2.x-t0.x;
			
			for(var i:int=0; i<total_height; i++)
			{
				second_half = i>dy1y0 || t1.y==t0.y;
				segment_height = second_half ? dy2y1 : dy1y0;
				
				alpha = i/total_height;
				beta = (i-(second_half ? dy1y0 : 0))/segment_height;
				
				A.x = t0.x+(dx2x0)*alpha;
				A.y = t0.y+(dy2y0)*alpha;
				B.x = second_half ? t1.x+(dx2x1)*beta : t0.x+(dx1x0)*beta;
				B.y = second_half ? t1.y+(dy2y1)*beta : t0.y+(dy1y0)*beta;
				 
				uvA.x = uv0.x + (uv2.x-uv0.x)*alpha;
				uvA.y = uv0.y + (uv2.y-uv0.y)*alpha;
				
				uvB.x = second_half ? uv1.x+(uv2.x-uv1.x)*beta : uv0.x+(uv1.x-uv0.x)*beta;
				uvB.y = second_half ? uv1.y+(uv2.y-uv1.y)*beta : uv0.y+(uv1.y-uv0.y)*beta;
				
				if (A.x>B.x)
				{//std::swap(A, B);
					vectorTemp = A;
					A = B;
					B = vectorTemp;
					
					vectorTemp = uvA;
					uvA = uvB;
					uvB = vectorTemp;
				}
		        for (var j:int=A.x; j<=B.x; j++) 
				{
		            var phi:Number = B.x==A.x ? 1. : (j-A.x)/(B.x-A.x);
		            
		            P.x = A.x + (B.x-A.x)*phi;
		            P.y = A.y + (B.y-A.y)*phi;
		            P.z = A.z + (B.z-A.z)*phi;
		            
		            uvP.x = uvA.x + (uvB.x-uvA.x)*phi;
		            uvP.y = uvA.y + (uvB.y-uvA.y)*phi;
		            uvP.z = uvA.z + (uvB.z-uvA.z)*phi;
		            
		            var idx:int = P.x+P.y*image.width;
		            if (zbuffer[idx]<P.z) 
		            {
		                zbuffer[idx] = P.z;
		                image.setPixel(j, t0.y+i, texture.getPixel(uvP.x, uvP.y));
		            }
		        }
			}
		}
		public function triangleWithZBuffer(t0:Vector3D, t1:Vector3D, t2:Vector3D, image:BitmapData, color:Number, zbuffer:Array):void
		{
			if (t0.y==t1.y && t0.y==t2.y) return; // i dont care about degenerate triangles
		   
			// sort the vertices, t0, t1, t2 lower-to-upper (bubblesort yay!)
			var arr:Array = [t0, t1, t2];
				arr.sort(function(p0:Vector3D, p1:Vector3D):int{
					if(p0.y > p1.y){ return 1; }
					else{ return -1; }
				});
			t0 = arr[0];
			t1 = arr[1];
			t2 = arr[2];
			
			// ------------
			var vectorTemp:Vector3D;
			var segment_height:int;
			var alpha:Number;
			var beta:Number;
			var A:Vector3D = new Vector3D();
			var B:Vector3D = new Vector3D();
			var P:Vector3D = new Vector3D();
			var second_half:Boolean;
			// ------------
			
			var total_height:int = t2.y-t0.y;
			
			var dy1y0:Number = t1.y-t0.y;
			var dy2y1:Number = t2.y-t1.y;
			var dy2y0:Number = t2.y-t0.y;
			
			var dx1x0:Number = t1.x-t0.x;
			var dx2x1:Number = t2.x-t1.x;
			var dx2x0:Number = t2.x-t0.x;
			
			for(var i:int=0; i<total_height; i++)
			{
				second_half = i>dy1y0 || t1.y==t0.y;
				segment_height = second_half ? dy2y1 : dy1y0;
				
				alpha = i/total_height;
				beta = (i-(second_half ? dy1y0 : 0))/segment_height;
				
				A.x = t0.x+(dx2x0)*alpha;
				A.y = t0.y+(dy2y0)*alpha;
				B.x = second_half ? t1.x+(dx2x1)*beta : t0.x+(dx1x0)*beta;
				B.y = second_half ? t1.y+(dy2y1)*beta : t0.y+(dy1y0)*beta;
				
				if (A.x>B.x)
				{//std::swap(A, B);
					vectorTemp = A;
					A = B;
					B = vectorTemp;
				}
		        for (var j:int=A.x; j<=B.x; j++) 
				{
		            
		            var phi:Number = B.x==A.x ? 1. : (j-A.x)/(B.x-A.x);
		            
		            P.x = A.x + (B.x-A.x)*phi;
		            P.y = A.y + (B.y-A.y)*phi;
		            P.z = A.z + (B.z-A.z)*phi;
		            var idx:int = P.x+P.y*image.width;
		            if (zbuffer[idx]<P.z) 
		            {
		                zbuffer[idx] = P.z;
		                image.setPixel(j, t0.y+i, color);
		            }
		        }
			}
		}
		public function triangleBitmap(t0:Vector3D, t1:Vector3D, t2:Vector3D, image:BitmapData, color:Number):void
		{
			if (t0.y==t1.y && t0.y==t2.y) return; // i dont care about degenerate triangles
		   
			// sort the vertices, t0, t1, t2 lower-to-upper (bubblesort yay!)
			var arr:Array = [t0, t1, t2];
				arr.sort(function(p0:Vector3D, p1:Vector3D):int{
					if(p0.y > p1.y){ return 1; }
					else{ return -1; }
				});
			t0 = arr[0];
			t1 = arr[1];
			t2 = arr[2];
			
			// ------------
			var vectorTemp:Vector3D;
			var segment_height:int;
			var alpha:Number;
			var beta:Number;
			var A:Vector3D = new Vector3D();
			var B:Vector3D = new Vector3D();
			var second_half:Boolean;
			// ------------
			
			var total_height:int = t2.y-t0.y;
			
			var dy1y0:Number = t1.y-t0.y;
			var dy2y1:Number = t2.y-t1.y;
			var dy2y0:Number = t2.y-t0.y;
			
			var dx1x0:Number = t1.x-t0.x;
			var dx2x1:Number = t2.x-t1.x;
			var dx2x0:Number = t2.x-t0.x;
			
			for(var i:int=0; i<total_height; i++)
			{
				second_half = i>dy1y0 || t1.y==t0.y;
				segment_height = second_half ? dy2y1 : dy1y0;
				
				alpha = i/total_height;
				beta = (i-(second_half ? dy1y0 : 0))/segment_height;
				
				A.x = t0.x+(dx2x0)*alpha;
				A.y = t0.y+(dy2y0)*alpha;
				B.x = second_half ? t1.x+(dx2x1)*beta : t0.x+(dx1x0)*beta;
				B.y = second_half ? t1.y+(dy2y1)*beta : t0.y+(dy1y0)*beta;
				
				if (A.x>B.x)
				{//std::swap(A, B);
					vectorTemp = A;
					A = B;
					B = vectorTemp;
				}
		        for (var j:int=A.x; j<=B.x; j++) 
				{
		            image.setPixel(j, t0.y+i, color);
		        }
			}
		}
	}
}
